We now know how to create many plot types using ggplot2, but often you want to customize your plots. Today, we’ll discuss common tools for customizing our plots.

To begin, make sure that you have the tidyverse loaded.

library(tidyverse)

Also, let’s start with our plot from the exercise

scorecard <- read_csv("https://github.com/cmsc205/data/raw/master/ScorecardSmallNarrow.csv")
p <- 
  scorecard %>%
  ggplot(aes(x=ADM_RATE, y=net_cost)) + 
  geom_point(alpha = 0.3, color="blue") + 
  facet_grid(CONTROL ~ income_group) +
  geom_smooth(color="red") + 
  ylim(0, 50000)
p

Adding titles, axis labels, and legend labels

Good labels are critical for making your plots accessible to a wider audience. It’s important to ensure axis and legend labels display the full variable name (or a logical abbreviaition), but this does not always happen by default.

To add/alter these annotations we simply add a new layer using the labs function.

Adding a title

p <- p + labs(title = "Average Net Cost per Year at U.S. Colleges")
p

Adding a subtitle

p <- p + labs(subtitle = "By income quintile")
p

Changing the axis labels

p + labs(x = "Admissions rate, %", 
         y = "Net cost per year, $'000")

Changing the legend labels

scorecard %>%
  ggplot(aes(x=ADM_RATE, y=net_cost, color=ADM_RATE)) + 
  geom_point(alpha = 0.3) + 
  facet_grid(CONTROL ~ income_group) +
  geom_smooth(color="darkorange") + 
  ylim(0, 50000) +
  labs(title = "Average Net Cost per Year at U.S. Colleges",
       subtitle = "By income quintile",
       x = "Admissions rate, %", 
       y = "Net cost per year, $'000",
       color = "Admissions\nRate")

Ordering factors

Sometimes we need to order the levels of a factor to make a plot meaningful.

To examine this, let’s look at a new data set which contains informatio on the 10 most popular baby names in 2014.

babynames <- read_csv("https://github.com/cmsc205/data/raw/master/top10babynames2014.csv")
babynames %>%
  ggplot(aes(x = name, y = n, fill = sex)) +
  geom_bar(stat = "identity")

To do this with respect to another variable we can use the reorder function.

babynames$name <- reorder(babynames$name, FUN = identity, babynames$n)
p2 <- babynames %>%
  ggplot(aes(x = name, y = n, fill = sex)) +
  geom_bar(stat = "identity") + 
  labs(title = "Top 10 Baby Names of 2014", x = NULL, y = "Count") +
  coord_flip()

Choosing color palettes

ggplot2 does not choose the nicest looking palettes, and the palettes are typically not colorblind friendly. Luckily, it’s quite easy to change the color palettes you use.

Manual adjustments

To manually adjust the colors we can use the functions scale_color_manual or scale_fill_manual

p2 + scale_fill_manual(values = c("deeppink", "steelblue"))

Using RColorBrewer

You can let the RColorBrewer package choose the colors for you using the color_scale_brewer and fill_scale_brewer functions.

p2 + scale_fill_brewer(palette = "Dark2")

You can see all of the possible palettes in the package by running

RColorBrewer::display.brewer.all()

Using viridis

If you install the viridis package (this might not be on the server), then you can use the scale_color_viridis and scale_fill_viridis functions.

library(viridis)
p2 + scale_fill_viridis(discrete = TRUE)

A colorblind friendly palette

The ggthemes package contains a colorblind-friendly palette, which can be adopted using the scale_color_colorblind and scale_fill_colorblind functions.

library(ggthemes)
p2 + scale_fill_colorblind()

Choosing themes

By default ggplot2 uses a grey background and guidlines on a plot; however, we don’t always want our plots to appear this way. To change this the appearance, we need to work with themes.

The ggthemes package offers many additional choices.

We can use an existing theme just like adding a layer.

p + theme_minimal()

p + theme_hc()

Customizing themes

Sometimes the ggthemes package won’t do exactly what you want so you will have to dig into ggplot2 a bit deeper and create your own theme.

See ?theme for a list of all of the components that you can modify.

babynames %>%
  ggplot(aes(x = name, y = n)) +
  geom_bar(stat = "identity") + 
  geom_text(aes(label = n), vjust=1.5, color = "white") +
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        panel.background = element_blank(),
        axis.ticks.x = element_blank(),
        axis.ticks.y = element_blank(),
        axis.text.y = element_blank(),
        axis.text.x = element_text(vjust = -2))

LS0tCnRpdGxlOiAiQ3VzdG9taXppbmcgUGxvdHMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCldlIG5vdyBrbm93IGhvdyB0byBjcmVhdGUgbWFueSBwbG90IHR5cGVzIHVzaW5nIGBnZ3Bsb3QyYCwgYnV0IG9mdGVuIHlvdSB3YW50IHRvIGN1c3RvbWl6ZSB5b3VyIHBsb3RzLiBUb2RheSwgd2UnbGwgZGlzY3VzcyBjb21tb24gdG9vbHMgZm9yIGN1c3RvbWl6aW5nIG91ciBwbG90cy4KClRvIGJlZ2luLCBtYWtlIHN1cmUgdGhhdCB5b3UgaGF2ZSB0aGUgYHRpZHl2ZXJzZWAgbG9hZGVkLgoKYGBge3IgbWVzc2FnZT1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKQWxzbywgbGV0J3Mgc3RhcnQgd2l0aCBvdXIgcGxvdCBmcm9tIHRoZSBleGVyY2lzZQoKYGBge3J9CnNjb3JlY2FyZCA8LSByZWFkX2NzdigiaHR0cHM6Ly9naXRodWIuY29tL2Ntc2MyMDUvZGF0YS9yYXcvbWFzdGVyL1Njb3JlY2FyZFNtYWxsTmFycm93LmNzdiIpCmBgYAoKYGBge3J9CnAgPC0gCiAgc2NvcmVjYXJkICU+JQogIGdncGxvdChhZXMoeD1BRE1fUkFURSwgeT1uZXRfY29zdCkpICsgCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMywgY29sb3I9ImJsdWUiKSArIAogIGZhY2V0X2dyaWQoQ09OVFJPTCB+IGluY29tZV9ncm91cCkgKwogIGdlb21fc21vb3RoKGNvbG9yPSJyZWQiKSArIAogIHlsaW0oMCwgNTAwMDApCnAKYGBgCgoKIyBBZGRpbmcgdGl0bGVzLCBheGlzIGxhYmVscywgYW5kIGxlZ2VuZCBsYWJlbHMKCgpHb29kIGxhYmVscyBhcmUgY3JpdGljYWwgZm9yIG1ha2luZyB5b3VyIHBsb3RzIGFjY2Vzc2libGUgdG8gYSB3aWRlciBhdWRpZW5jZS4gSXQncyBpbXBvcnRhbnQgdG8gZW5zdXJlIGF4aXMgYW5kIGxlZ2VuZCBsYWJlbHMgZGlzcGxheSB0aGUgZnVsbCB2YXJpYWJsZSBuYW1lIChvciBhIGxvZ2ljYWwgYWJicmV2aWFpdGlvbiksIGJ1dCB0aGlzIGRvZXMgbm90IGFsd2F5cyBoYXBwZW4gYnkgZGVmYXVsdC4gCgpUbyBhZGQvYWx0ZXIgdGhlc2UgYW5ub3RhdGlvbnMgd2Ugc2ltcGx5IGFkZCBhIG5ldyBsYXllciB1c2luZyB0aGUgYGxhYnNgIGZ1bmN0aW9uLgoKCiMjIyMgQWRkaW5nIGEgdGl0bGUKCmBgYHtyfQpwIDwtIHAgKyBsYWJzKHRpdGxlID0gIkF2ZXJhZ2UgTmV0IENvc3QgcGVyIFllYXIgYXQgVS5TLiBDb2xsZWdlcyIpCnAKYGBgCgojIyMjIEFkZGluZyBhIHN1YnRpdGxlCgpgYGB7cn0KcCA8LSBwICsgbGFicyhzdWJ0aXRsZSA9ICJCeSBpbmNvbWUgcXVpbnRpbGUiKQpwCmBgYAoKIyMjIyBDaGFuZ2luZyB0aGUgYXhpcyBsYWJlbHMKCmBgYHtyfQpwICsgbGFicyh4ID0gIkFkbWlzc2lvbnMgcmF0ZSwgJSIsIAogICAgICAgICB5ID0gIk5ldCBjb3N0IHBlciB5ZWFyLCAkJzAwMCIpCmBgYAoKCiMjIyMgQ2hhbmdpbmcgdGhlIGxlZ2VuZCBsYWJlbHMKCmBgYHtyfQpzY29yZWNhcmQgJT4lCiAgZ2dwbG90KGFlcyh4PUFETV9SQVRFLCB5PW5ldF9jb3N0LCBjb2xvcj1BRE1fUkFURSkpICsgCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMykgKyAKICBmYWNldF9ncmlkKENPTlRST0wgfiBpbmNvbWVfZ3JvdXApICsKICBnZW9tX3Ntb290aChjb2xvcj0iZGFya29yYW5nZSIpICsgCiAgeWxpbSgwLCA1MDAwMCkgKwogIGxhYnModGl0bGUgPSAiQXZlcmFnZSBOZXQgQ29zdCBwZXIgWWVhciBhdCBVLlMuIENvbGxlZ2VzIiwKICAgICAgIHN1YnRpdGxlID0gIkJ5IGluY29tZSBxdWludGlsZSIsCiAgICAgICB4ID0gIkFkbWlzc2lvbnMgcmF0ZSwgJSIsIAogICAgICAgeSA9ICJOZXQgY29zdCBwZXIgeWVhciwgJCcwMDAiLAogICAgICAgY29sb3IgPSAiQWRtaXNzaW9uc1xuUmF0ZSIpCmBgYAoKCiMgT3JkZXJpbmcgZmFjdG9ycwoKU29tZXRpbWVzIHdlIG5lZWQgdG8gb3JkZXIgdGhlIGxldmVscyBvZiBhIGZhY3RvciB0byBtYWtlIGEgcGxvdCBtZWFuaW5nZnVsLgoKVG8gZXhhbWluZSB0aGlzLCBsZXQncyBsb29rIGF0IGEgbmV3IGRhdGEgc2V0IHdoaWNoIGNvbnRhaW5zIGluZm9ybWF0aW8gb24gdGhlIDEwIG1vc3QgcG9wdWxhciBiYWJ5IG5hbWVzIGluIDIwMTQuCgpgYGB7cn0KYmFieW5hbWVzIDwtIHJlYWRfY3N2KCJodHRwczovL2dpdGh1Yi5jb20vY21zYzIwNS9kYXRhL3Jhdy9tYXN0ZXIvdG9wMTBiYWJ5bmFtZXMyMDE0LmNzdiIpCmBgYAoKYGBge3J9CmJhYnluYW1lcyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBuYW1lLCB5ID0gbiwgZmlsbCA9IHNleCkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikKYGBgCgoKClRvIGRvIHRoaXMgd2l0aCByZXNwZWN0IHRvIGFub3RoZXIgdmFyaWFibGUgd2UgY2FuIHVzZSB0aGUgYHJlb3JkZXJgIGZ1bmN0aW9uLiAKCmBgYHtyfQpiYWJ5bmFtZXMkbmFtZSA8LSByZW9yZGVyKGJhYnluYW1lcyRuYW1lLCBGVU4gPSBpZGVudGl0eSwgYmFieW5hbWVzJG4pCgpwMiA8LSBiYWJ5bmFtZXMgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbmFtZSwgeSA9IG4sIGZpbGwgPSBzZXgpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsgCiAgbGFicyh0aXRsZSA9ICJUb3AgMTAgQmFieSBOYW1lcyBvZiAyMDE0IiwgeCA9IE5VTEwsIHkgPSAiQ291bnQiKSArCiAgY29vcmRfZmxpcCgpCnAyCmBgYAoKCgojIENob29zaW5nIGNvbG9yIHBhbGV0dGVzCgpgZ2dwbG90MmAgZG9lcyBub3QgY2hvb3NlIHRoZSBuaWNlc3QgbG9va2luZyBwYWxldHRlcywgYW5kIHRoZSBwYWxldHRlcyBhcmUgdHlwaWNhbGx5IG5vdCBjb2xvcmJsaW5kIGZyaWVuZGx5LiBMdWNraWx5LCBpdCdzIHF1aXRlIGVhc3kgdG8gY2hhbmdlIHRoZSBjb2xvciBwYWxldHRlcyB5b3UgdXNlLgoKIyMjIyBNYW51YWwgYWRqdXN0bWVudHMKClRvIG1hbnVhbGx5IGFkanVzdCB0aGUgY29sb3JzIHdlIGNhbiB1c2UgdGhlIGZ1bmN0aW9ucyBgc2NhbGVfY29sb3JfbWFudWFsYCBvciBgc2NhbGVfZmlsbF9tYW51YWxgCgpgYGB7cn0KcDIgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJkZWVwcGluayIsICJzdGVlbGJsdWUiKSkKYGBgCgoKIyMjIyBVc2luZyBSQ29sb3JCcmV3ZXIKCllvdSBjYW4gbGV0IHRoZSBSQ29sb3JCcmV3ZXIgcGFja2FnZSBjaG9vc2UgdGhlIGNvbG9ycyBmb3IgeW91IHVzaW5nIHRoZSBgY29sb3Jfc2NhbGVfYnJld2VyYCBhbmQgYGZpbGxfc2NhbGVfYnJld2VyYCBmdW5jdGlvbnMuIAoKYGBge3J9CnAyICsgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpCmBgYAoKCllvdSBjYW4gc2VlIGFsbCBvZiB0aGUgcG9zc2libGUgcGFsZXR0ZXMgaW4gdGhlIHBhY2thZ2UgYnkgcnVubmluZyAKCmBgYHtyfQpSQ29sb3JCcmV3ZXI6OmRpc3BsYXkuYnJld2VyLmFsbCgpCmBgYAoKCiMjIyMgVXNpbmcgdmlyaWRpcwoKSWYgeW91IGluc3RhbGwgdGhlIHZpcmlkaXMgcGFja2FnZSAodGhpcyBtaWdodCBub3QgYmUgb24gdGhlIHNlcnZlciksIHRoZW4geW91IGNhbiB1c2UgdGhlIGBzY2FsZV9jb2xvcl92aXJpZGlzYCBhbmQgYHNjYWxlX2ZpbGxfdmlyaWRpc2AgZnVuY3Rpb25zLgoKYGBge3J9CmxpYnJhcnkodmlyaWRpcykKcDIgKyBzY2FsZV9maWxsX3ZpcmlkaXMoZGlzY3JldGUgPSBUUlVFKQpgYGAKCiMjIyMgQSBjb2xvcmJsaW5kIGZyaWVuZGx5IHBhbGV0dGUKClRoZSBgZ2d0aGVtZXNgIHBhY2thZ2UgY29udGFpbnMgYSBjb2xvcmJsaW5kLWZyaWVuZGx5IHBhbGV0dGUsIHdoaWNoIGNhbiBiZSBhZG9wdGVkIHVzaW5nIHRoZSBgc2NhbGVfY29sb3JfY29sb3JibGluZGAgYW5kIGBzY2FsZV9maWxsX2NvbG9yYmxpbmRgIGZ1bmN0aW9ucy4KCgpgYGB7cn0KbGlicmFyeShnZ3RoZW1lcykKcDIgKyBzY2FsZV9maWxsX2NvbG9yYmxpbmQoKQpgYGAKCgoKCiMgQ2hvb3NpbmcgdGhlbWVzCgpCeSBkZWZhdWx0IGBnZ3Bsb3QyYCB1c2VzIGEgZ3JleSBiYWNrZ3JvdW5kIGFuZCBndWlkbGluZXMgb24gYSBwbG90OyBob3dldmVyLCB3ZSBkb24ndCBhbHdheXMgd2FudCBvdXIgcGxvdHMgdG8gYXBwZWFyIHRoaXMgd2F5LiBUbyBjaGFuZ2UgdGhpcyB0aGUgYXBwZWFyYW5jZSwgd2UgbmVlZCB0byB3b3JrIHdpdGggdGhlbWVzLgoKVGhlIGBnZ3RoZW1lc2AgcGFja2FnZSBvZmZlcnMgbWFueSBhZGRpdGlvbmFsIFtjaG9pY2VzXShodHRwczovL2dpdGh1Yi5jb20vanJub2xkL2dndGhlbWVzKS4gCgpXZSBjYW4gdXNlIGFuIGV4aXN0aW5nIHRoZW1lIGp1c3QgbGlrZSBhZGRpbmcgYSBsYXllci4KCgpgYGB7cn0KcCArIHRoZW1lX21pbmltYWwoKQpgYGAKCgpgYGB7cn0KcCArIHRoZW1lX2hjKCkKYGBgCgoKIyBDdXN0b21pemluZyB0aGVtZXMKClNvbWV0aW1lcyB0aGUgYGdndGhlbWVzYCBwYWNrYWdlIHdvbid0IGRvIGV4YWN0bHkgd2hhdCB5b3Ugd2FudCBzbyB5b3Ugd2lsbCBoYXZlIHRvIGRpZyBpbnRvIGBnZ3Bsb3QyYCBhIGJpdCBkZWVwZXIgYW5kIGNyZWF0ZSB5b3VyIG93biB0aGVtZS4KClNlZSBgP3RoZW1lYCBmb3IgYSBsaXN0IG9mIGFsbCBvZiB0aGUgY29tcG9uZW50cyB0aGF0IHlvdSBjYW4gbW9kaWZ5LgoKCmBgYHtyfQpiYWJ5bmFtZXMgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbmFtZSwgeSA9IG4pKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsgCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG4pLCB2anVzdD0xLjUsIGNvbG9yID0gIndoaXRlIikgKwogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCg==